home *** CD-ROM | disk | FTP | other *** search
/ 3D GFX / 3D GFX.iso / amiutils / i_l / irit5 / irit / inptprsr.c < prev    next >
C/C++ Source or Header  |  1995-12-30  |  45KB  |  1,269 lines

  1. /*****************************************************************************
  2. *   "Irit" - the 3d (not only polygonal) solid modeller.             *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.2, Mar. 1990   *
  5. ******************************************************************************
  6. *   Module to convert infix expression given as    ascii stream sequence into   *
  7. * a binary tree, and evaluate it.                         *
  8. *   All the objects are handled the same but the numerical one, which is     *
  9. * moved as a RealType and not as an object (only internally within this         *
  10. * module) as it is frequently used and consumes much less memory this way.   *
  11. *****************************************************************************/
  12.  
  13. #include <stdio.h>
  14. #include <ctype.h>
  15. #include <math.h>
  16. #include <string.h>
  17. #include "program.h"
  18. #include "allocate.h"
  19. #include "ctrl-brk.h"
  20. #include "inptprsg.h"
  21. #include "inptprsl.h"
  22. #include "objects.h"
  23. #include "overload.h"
  24. #include "windows.h"
  25.  
  26. char IPGlblCharData[INPUT_LINE_LEN];          /* Used for both parse & eval. */
  27.  
  28. static int IPGlblILastToken;              /* Globals used by parser. */
  29. static InptPrsrEvalErrType
  30.     IPGlblParseError = IPE_NO_ERR;
  31. static UserDefinedFuncDefType
  32.     *IPGlblUserFunc = NULL;
  33. static FileStackStruct FileStack[FILE_STACK_SIZE];    /* Include file stack. */
  34. static int
  35.     GlblEchoSource = TRUE,
  36.     FileStackPtr = 0;
  37. static char
  38.     UnGetChar = 0;
  39.  
  40. /* Operator preceeding parser stack, and stack pointer: */
  41. static ParseTree *Stack[MAX_PARSER_STACK];
  42. static int
  43.     ParserStackPointer = 0;
  44.  
  45. #ifdef DEBUG1
  46.     int MaxStackPointer = 0;          /* Measure maximum depth of stack. */
  47. #endif /* DEBUG1 */
  48.  
  49. static ParseTree *GenInputParseTree(void);
  50. static ParseTree *OperatorPrecedence(void);
  51. static int TestPreceeding(int Token1, int Token2);
  52. static char *UpdateCharErrorAux(int Token, ParseTree *Node);
  53. static int GetToken(RealType *Data);
  54. static int GetVarFuncToken(char *Token, RealType *Data);
  55. static void InptPrsrUnGetC(char c);
  56. static char InptPrsrGetC(int InString);
  57.  
  58. /*****************************************************************************
  59. * DESCRIPTION:                                                               M
  60. * Main module routine - generate parse tree and then tries to evaluate it.   M
  61. *   Returns TRUE if succesfull, otherwise check IPGlblParseError/EvalError.  M
  62. *                                                                            *
  63. * PARAMETERS:                                                                M
  64. *   None                                                                     M
  65. *                                                                            *
  66. * RETURN VALUE:                                                              M
  67. *   int:         TRUE if successful, FALSE otherwise.                        M
  68. *                                                                            *
  69. * KEYWORDS:                                                                  M
  70. *   InputParser                                                              M
  71. *****************************************************************************/
  72. int InputParser(void)
  73. {
  74.     ParseTree *PTree;
  75.  
  76.     if (GlblFatalError) {
  77.     GlblFatalError = FALSE;
  78.     FlushToEndOfExpr(FALSE);      /* Close all include files if any. */
  79.     return TRUE;
  80.     }
  81.  
  82.     PTree = GenInputParseTree();             /* Generate parse tree. */
  83.  
  84.     if (IPGlblParseError == IPE_NO_ERR) {
  85. #    ifdef DEBUG1
  86.         fprintf(stderr, "\nInput generated Parse tree (Max stack = %d)\n",
  87.                             MaxStackPointer);
  88.         InptPrsrPrintTree(PTree, NULL);
  89.         fprintf(stderr, "\n");
  90. #    endif /* DEBUG1 */
  91.     if (InptPrsrTypeCheck(PTree, 0) == ERROR_EXPR) {   /* Type checking. */
  92.         InptPrsrFreeTree(PTree);             /* Not needed any more. */
  93.         FlushToEndOfExpr(TRUE);/* Close all include files, & flush stdin.*/
  94.         return FALSE;
  95.     }
  96.  
  97.     InptPrsrEvalTree(PTree, 0);                 /* Evaluate it. */
  98.     if (IPGlblEvalError != IPE_NO_ERR) {
  99.         FlushToEndOfExpr(TRUE); /* Close include files, and flush stdin. */
  100.         return FALSE;
  101.     }
  102.     }
  103.     else {
  104.     FlushToEndOfExpr(TRUE); /* Close all include files, and flush stdin. */
  105.     return FALSE;
  106.     }
  107.  
  108.     InptPrsrFreeTree(PTree);                 /* Not needed any more. */
  109.  
  110.     return !(IPGlblParseError || IPGlblEvalError);
  111. }
  112.  
  113. /*****************************************************************************
  114. * DESCRIPTION:                                                               *
  115. * Routine to convert the expression from stream f into a binary tree.        *
  116. *   Algorithm: Using operator precedence with the following grammer:         *
  117. * EXPR    ::= EXPR    |  EXPR + EXPR    |  EXPR - EXPR                       *
  118. * EXPR    ::= EXPR    |  EXPR * EXPR    |  EXPR / EXPR                       *
  119. * EXPR    ::= EXPR    |  EXPR ^ EXPR                                         *
  120. * EXPR    ::= EXPR    |  EXPR , EXPR    |  EXPR = EXPR                       *
  121. * EXPR    ::= NUMBER  |  -EXPR          |  (EXPR)        |  FUNCTION         *
  122. * FUCTION ::= FUNC(EXPR , EXPR , ...)                         *
  123. *   Where FUNC might be function like arithmetics (SIN, COS etc.).         *
  124. *   Note that FUNC might have more than one operand, seperated by ','.         *
  125. *                                                                            *
  126. *   Note the stream is terminated by semicolon character ';'.             *
  127. *                                                                            *
  128. *   Left associativity for +, -, *, /, ^.                                    *
  129. *   Precedence of operators is as usual:                                     *
  130. *     <Highest> {unar minus}   {^}   {*, /}   {+, -} <Lowest>             *
  131. *                                                                            *
  132. *   Returns NULL if an error was found, and error is in IPGlblParseError     *
  133. *                                                                            *
  134. * PARAMETERS:                                                                *
  135. *   None                                                                     *
  136. *                                                                            *
  137. * RETURN VALUE:                                                              *
  138. *   ParseTree *:   Constructed parsed tree.                                  *
  139. *****************************************************************************/
  140. static ParseTree *GenInputParseTree(void)
  141. {
  142.     ParseTree *Root;
  143.     int i;
  144.  
  145.     IPGlblILastToken = 0;    /* Used to hold last token read from stream. */
  146.     IPGlblParseError = IPE_NO_ERR;             /* No errors so far ... */
  147.  
  148.     Root = OperatorPrecedence();
  149.  
  150.     if (IPGlblParseError) {
  151.     /* Free partialy allocated tree. */
  152.     for (i = 0; i <= ParserStackPointer; i++)
  153.         InptPrsrFreeTree(Stack[i]);
  154.         return NULL;                          /* Error ! */
  155.     }
  156.     else
  157.     return Root;
  158. }
  159.  
  160. /*****************************************************************************
  161. * DESCRIPTION:                                                               M
  162. * Routine to allocate new ParseTree expression node.                 M
  163. *                                                                            *
  164. * PARAMETERS:                                                                M
  165. *   None                                                                     M
  166. *                                                                            *
  167. * RETURN VALUE:                                                              M
  168. *   ParseTree *:   Allocate a ParseTree node.                                M
  169. *                                                                            *
  170. * KEYWORDS:                                                                  M
  171. *   ExprMalloc                                                               M
  172. *****************************************************************************/
  173. ParseTree *ExprMalloc(void)
  174. {
  175.     ParseTree *p;
  176.  
  177.     p = (ParseTree *) IritMalloc(sizeof(ParseTree));
  178.     p -> Right = p -> Left = NULL;
  179.     p -> NodeKind = IP_OBJ_UNDEF;
  180.     p -> PObj = NULL;
  181.     p -> UserFunc = NULL;
  182.     return p;
  183. }
  184.  
  185. /*****************************************************************************
  186. * DESCRIPTION:                                                               M
  187. * Routine to free one expression node.                         M
  188. *                                                                            *
  189. * PARAMETERS:                                                                M
  190. *   Ptr:       ParseTree to free.                                            M
  191. *                                                                            *
  192. * RETURN VALUE:                                                              M
  193. *   void                                                                     M
  194. *                                                                            *
  195. * KEYWORDS:                                                                  M
  196. *   ExprFree                                                                 M
  197. *****************************************************************************/
  198. void ExprFree(ParseTree *Ptr)
  199. {
  200.     IritFree((VoidPtr) Ptr);
  201. }
  202.  
  203. /*****************************************************************************
  204. * DESCRIPTION:                                                               *
  205. * Routine to actually parse using operator precedence.                       *
  206. * Few Notes:                                                                 *
  207. * 1. Parse the input with the help of GetToken routine. Input is redirected  *
  208. *    using the FileStack.                             *
  209. * 2. All tokens must be in the range of 0..999 as we use the numbers above   *
  210. *    it (adding 1000) to deactivate them in the handle searching (i.e. when  *
  211. *    they were reduced to sub.-expression).                                  *
  212. * 3. Returns NULL pointer in case of an error.                     *
  213. * 4. See "Compilers - principles, techniques and tools" by Aho, Sethi &      *
  214. *    Ullman,   pages 207-210.                                                *
  215. *                                                                            *
  216. * PARAMETERS:                                                                *
  217. *   None                                                                     *
  218. *                                                                            *
  219. * RETURN VALUE:                                                              *
  220. *   ParseTree *:   Returned parsed tree.                                     *
  221. *****************************************************************************/
  222. static ParseTree *OperatorPrecedence(void)
  223. {
  224.     int Token, LowHandle, Temp1, Temp2;
  225.     RealType Data;
  226.  
  227. #   ifdef DEBUG1
  228.     MaxStackPointer = 0;
  229. #   endif /* DEBUG1 */
  230.  
  231.     ParserStackPointer = 0;
  232.  
  233.     /* Push the start symbol on stack (node pointer points on tos): */
  234.     Stack[ParserStackPointer] = ExprMalloc();
  235.     Stack[ParserStackPointer] -> NodeKind = TOKENSTART;
  236.     Stack[ParserStackPointer] -> Right =
  237.     Stack[ParserStackPointer] -> Left = NULL;
  238.  
  239.     Token = GetToken(&Data);      /* Get one look ahead token to start with. */
  240.  
  241.     while (TRUE) {
  242.         if (IPGlblParseError)
  243.         return NULL;
  244.  
  245.         Temp1 = ParserStackPointer;       /* Find top active token (<1000). */
  246.         while (Stack[Temp1] -> NodeKind >= 1000)
  247.         Temp1--;
  248.         /* Now test to see if the new token completes an handle: */
  249.         if (TestPreceeding(Stack[Temp1] -> NodeKind, Token)) {
  250.             switch (Token) {
  251.         case CLOSPARA:
  252.                     if (Stack[Temp1] -> NodeKind == OPENPARA) {
  253.             ExprFree(Stack[Temp1]);         /* Free open paran. */
  254.             Stack[Temp1] = NULL;
  255.             /* If a parameter is introduced instead of function  */
  256.             /* it will be reduced already against "(" and it     */
  257.             /* probably was missspelled function...             */
  258.                         if (Stack[Temp1 - 1] -> NodeKind == PARAMETER + 1000) {
  259.                 strcpy(IPGlblCharData,
  260.                     Stack[Temp1 - 1] -> PObj -> Name);
  261.                 IPGlblParseError = IP_ERR_UNDEF_FUNC;
  262.                 return NULL;
  263.             }
  264.  
  265.             if (IS_USER_FUNCTION(Stack[Temp1 - 1] -> NodeKind)) {
  266.                 if (ParserStackPointer - Temp1 == 1) {
  267.                 Stack[ParserStackPointer] -> NodeKind -= 1000;
  268.                 Stack[Temp1 - 1] -> NodeKind += 1000;
  269.                 Stack[Temp1 - 1] -> Right =
  270.                     Stack[ParserStackPointer];
  271.                 ParserStackPointer -= 2;
  272.                 }
  273.                 else {
  274.                 Stack[Temp1 - 1] -> NodeKind += 1000;
  275.                 Stack[Temp1 - 1] -> Right = NULL;
  276.                 ParserStackPointer--;
  277.                 }
  278.             }
  279.                         else if (IS_NO_PARAM_FUNC(Stack[Temp1 - 1] -> NodeKind)) {
  280.                 if (ParserStackPointer - Temp1 == 1) {
  281.                     UpdateCharError("",
  282.                         Stack[Temp1 - 1] -> NodeKind,
  283.                         Stack[Temp1 - 1]);
  284.                 IPGlblParseError = IP_ERR_NO_PARAM_FUNC;
  285.                 return NULL;
  286.                 }
  287.                 Stack[Temp1 - 1] -> NodeKind += 1000;
  288.                 Stack[Temp1 - 1] -> Right = NULL;
  289.                 ParserStackPointer--;
  290.                         }
  291.                         else if (IS_FUNCTION(Stack[Temp1 - 1] -> NodeKind)) {
  292.                 if (ParserStackPointer - Temp1 != 1) {
  293.                     UpdateCharError("",
  294.                         Stack[Temp1 - 1] -> NodeKind,
  295.                         Stack[Temp1 - 1]);
  296.                     IPGlblParseError = IP_ERR_PARAM_FUNC;
  297.                     return NULL;
  298.                 }
  299.                 Stack[ParserStackPointer] -> NodeKind -= 1000;
  300.                 Stack[Temp1 - 1] -> NodeKind += 1000;
  301.                 Stack[Temp1 - 1] -> Right =
  302.                     Stack[ParserStackPointer];
  303.                 ParserStackPointer -= 2;
  304.                     }
  305.                         else {
  306.                 if (ParserStackPointer - Temp1 != 1) {
  307.                     IPGlblParseError = IP_ERR_PARAM_MATCH;
  308.                     return NULL;
  309.                 }
  310.                             Stack[Temp1] = Stack[ParserStackPointer--];
  311.             }
  312.                         Token = GetToken(&Data);       /* Get another token. */
  313.                         continue;
  314.             }
  315.             else if (Stack[Temp1] -> NodeKind == TOKENSTART) {
  316.             /* No match for this one! */
  317.                         IPGlblParseError = IP_ERR_PARAM_MATCH;
  318.             return NULL;
  319.             }
  320.             break;
  321.                 case TOKENEND:
  322.                     if (Stack[Temp1] -> NodeKind == TOKENSTART) {
  323.                         if (ParserStackPointer != 1) {
  324.                             IPGlblParseError = IP_ERR_WRONG_SYNTAX;
  325.                 return NULL;
  326.             }
  327.             InptPrsrFreeTree(Stack[Temp1]);      /* The TOKENSTART. */
  328.             Stack[1] -> NodeKind -= 1000;
  329.             return Stack[1];
  330.             }
  331.         }
  332.  
  333.             Temp2 = Temp1 - 1;          /* Find the lower bound of handle. */
  334.             while (Temp2 >= 0 && Stack[Temp2] -> NodeKind >= 1000)
  335.         Temp2--;
  336.             LowHandle = Temp2 + 1;
  337.             if (LowHandle < 1) {                  /* No low bound was found. */
  338.                 IPGlblParseError = IP_ERR_WRONG_SYNTAX;
  339.             return NULL;             /* We ignore data till now. */
  340.             }
  341.         switch (ParserStackPointer - LowHandle + 1) {
  342.         case 1: /* Its a scalar one - mark it as used (add 1000). */
  343.             switch (Stack[ParserStackPointer] -> NodeKind) {
  344.             case NUMBER:
  345.             case PARAMETER:
  346.             case STRING:
  347.                     Stack[ParserStackPointer] -> NodeKind += 1000;
  348.                 break;
  349.             default:
  350.                 UpdateCharError("Found ",
  351.                      Stack[ParserStackPointer] -> NodeKind,
  352.                      Stack[ParserStackPointer]);
  353.                 IPGlblParseError = IP_ERR_PARAM_EXPECT;
  354.                 return NULL;
  355.             }
  356.             break;
  357.         case 2: /* Its a monadic operator - create the subtree. */
  358.             switch (Stack[ParserStackPointer - 1] -> NodeKind) {
  359.                 case BOOL_NOT:
  360.                 case UNARMINUS:
  361.                     Stack[ParserStackPointer - 1] -> Right =
  362.                         Stack[ParserStackPointer];
  363.                     Stack[ParserStackPointer] -> NodeKind -= 1000;
  364.                     Stack[ParserStackPointer - 1] -> NodeKind += 1000;
  365.                     ParserStackPointer--;
  366.                     break;
  367.                 case OPENPARA:
  368.                 IPGlblParseError = IP_ERR_PARAM_MATCH;
  369.                 return NULL;
  370.                 default:
  371.                 if (IS_AN_OPERATOR(Stack[ParserStackPointer] ->
  372.                                                 NodeKind))
  373.                 UpdateCharError("Found ",
  374.                     Stack[ParserStackPointer] -> NodeKind,
  375.                         Stack[ParserStackPointer]);
  376.                 else
  377.                 UpdateCharError("Found ",
  378.                     Stack[ParserStackPointer - 1] -> NodeKind,
  379.                     Stack[ParserStackPointer - 1]);
  380.  
  381.                 IPGlblParseError = IP_ERR_ONE_OPERAND;
  382.                 return NULL;
  383.             }
  384.             break;
  385.         case 3: /* Its a diadic operator - create the subtree. */
  386.             switch (Stack[ParserStackPointer - 1] -> NodeKind) {
  387.                 case PLUS:
  388.                 case MINUS:
  389.                 case MULT:
  390.                 case DIV:
  391.                 case POWER:
  392.                 case COMMA:
  393.                 case EQUAL:
  394.                 case CMP_EQUAL:
  395.                 case CMP_NOTEQUAL:
  396.                 case CMP_LSEQUAL:
  397.                 case CMP_GTEQUAL:
  398.                 case CMP_LESS:
  399.                 case CMP_GREAT:
  400.                 case BOOL_AND:
  401.                 case BOOL_OR:
  402.                 case COLON:
  403.                     Stack[ParserStackPointer - 1] -> Right =
  404.                                   Stack[ParserStackPointer];
  405.                             Stack[ParserStackPointer - 1] -> Left =
  406.                                   Stack[ParserStackPointer - 2];
  407.                     Stack[ParserStackPointer - 2] -> NodeKind -= 1000;
  408.                     Stack[ParserStackPointer] -> NodeKind -= 1000;
  409.                     Stack[ParserStackPointer - 1] -> NodeKind += 1000;
  410.                     Stack[ParserStackPointer - 2] =
  411.                         Stack[ParserStackPointer - 1];
  412.                     ParserStackPointer -= 2;
  413.                             break;
  414.                         default:
  415.                 UpdateCharError("Found Operator ",
  416.                     Stack[ParserStackPointer - 1] -> NodeKind,
  417.                     Stack[ParserStackPointer - 1]);
  418.                 IPGlblParseError = IP_ERR_TWO_OPERAND;
  419.                 return NULL;
  420.             }
  421.             break;
  422.         default:
  423.             IPGlblParseError = IP_ERR_WRONG_SYNTAX;
  424.             return NULL;
  425.         }
  426.         }
  427.         else {         /* Push that token on stack - it is not handle yet. */
  428.         Stack[++ParserStackPointer] = ExprMalloc();
  429.  
  430. #        ifdef DEBUG1
  431.         if (MaxStackPointer < ParserStackPointer)
  432.             MaxStackPointer = ParserStackPointer;
  433. #        endif /* DEBUG1 */
  434.  
  435.             if (ParserStackPointer == MAX_PARSER_STACK - 1) {
  436.                 IPGlblParseError = IP_ERR_STACK_OV;
  437.         return NULL;             /* We ignore data till now. */
  438.         }
  439.             if ((Stack[ParserStackPointer] -> NodeKind = Token) == USERINSTDEF)
  440.         Stack[ParserStackPointer] -> UserFunc = IPGlblUserFunc;
  441.             Stack[ParserStackPointer] -> PObj = NULL;
  442.         Stack[ParserStackPointer] -> Right =
  443.         Stack[ParserStackPointer] -> Left = NULL;
  444.         if (Token == NUMBER) {
  445.         Stack[ParserStackPointer] -> PObj = GenNUMValObject(Data);
  446.         }
  447.         else if (Token == PARAMETER) {
  448.         if ((Stack[ParserStackPointer] -> PObj =
  449.                 GetObject(IPGlblCharData)) == NULL) {
  450.             /*   Its new one - allocate memory for it. Create a      */
  451.             /* numeric object as a reasonable default.             */
  452.             Stack[ParserStackPointer] -> PObj =
  453.             IPAllocObject(IPGlblCharData, IP_OBJ_UNDEF, NULL);
  454.             InsertObject(Stack[ParserStackPointer] -> PObj);
  455.         }
  456.         Stack[ParserStackPointer] -> PObj -> Count++;
  457.         }
  458.         else if (Token == STRING) {
  459.         Stack[ParserStackPointer] -> PObj =
  460.             IPAllocObject("", IP_OBJ_STRING, NULL);
  461.         strcpy(Stack[ParserStackPointer] -> PObj -> U.Str,
  462.                IPGlblCharData);
  463.         Stack[ParserStackPointer] -> PObj -> Count++;
  464.         }
  465.             Token = GetToken(&Data);       /* And get new token from stream. */
  466.     }
  467.     }
  468. }
  469.  
  470. /*****************************************************************************
  471. * DESCRIPTION:                                                               *
  472. * Routine to test precedence of two tokens. returns 0, <0 or >0 according to *
  473. * comparison results.                                                        *
  474. *                                                                            *
  475. * PARAMETERS:                                                                *
  476. *   Token1, Token2:   Tokens to compare.                                     *
  477. *                                                                            *
  478. * RETURN VALUE:                                                              *
  479. *   int:         <0, 0, >0 comparison's result.                              *
  480. *****************************************************************************/
  481. static int TestPreceeding(int Token1, int Token2)
  482. {
  483.     int Preced1 = 0,
  484.     Preced2 = 0;
  485.  
  486.     if ((Token1 >= 1000) || (Token2 >= 1000))
  487.     return FALSE;                     /* Ignore sub-expr. */
  488.  
  489.     if (IS_FUNCTION(Token1))
  490.     Preced1 = 160;
  491.     else {
  492.         switch (Token1) {
  493.         case TOKENSTART:
  494.         case TOKENEND:
  495.             Preced1 = 10;
  496.             break;
  497.         case OPENPARA:
  498.             Preced1 = 20;
  499.             break;
  500.             case COMMA:
  501.             Preced1 = 30;
  502.             break;
  503.             case COLON:
  504.             Preced1 = 40;
  505.             break;
  506.         case BOOL_AND:
  507.         case BOOL_OR:
  508.         Preced1 = 50;
  509.         break;
  510.             case EQUAL:
  511.         case CMP_EQUAL:
  512.         case CMP_NOTEQUAL:
  513.         case CMP_LSEQUAL:
  514.         case CMP_GTEQUAL:
  515.         case CMP_LESS:
  516.         case CMP_GREAT:
  517.             Preced1 = 55;
  518.             break;
  519.         case PLUS:
  520.         case MINUS:
  521.             Preced1 = 80;
  522.             break;
  523.         case MULT:
  524.         case DIV:
  525.             Preced1 = 100;
  526.             break;
  527.         case POWER:
  528.             Preced1 = 120;
  529.             break;
  530.         case UNARMINUS:
  531.         case BOOL_NOT:
  532.             Preced1 = 125;
  533.             break;
  534.             case NUMBER:
  535.             case PARAMETER:
  536.             case STRING:
  537.         case CLOSPARA:
  538.             Preced1 = 180;
  539.             break;
  540.  
  541.         }
  542.     }
  543.  
  544.     if (IS_FUNCTION(Token2))
  545.     Preced2 = 150;
  546.     else {
  547.         switch (Token2) {
  548.         case TOKENSTART:
  549.         case TOKENEND:
  550.             Preced2 = 0;
  551.             break;
  552.         case CLOSPARA:
  553.             Preced2 = 15;
  554.             break;
  555.         case COMMA:
  556.             Preced2 = 30;
  557.             break;
  558.         case COLON:
  559.             Preced2 = 40;
  560.             break;
  561.         case BOOL_AND:
  562.         case BOOL_OR:
  563.         Preced2 = 50;
  564.         break;
  565.         case EQUAL:
  566.         case CMP_EQUAL:
  567.         case CMP_NOTEQUAL:
  568.         case CMP_LSEQUAL:
  569.         case CMP_GTEQUAL:
  570.         case CMP_LESS:
  571.         case CMP_GREAT:
  572.             Preced2 = 55;
  573.             break;
  574.         case PLUS:
  575.         case MINUS:
  576.             Preced2 = 70;
  577.             break;
  578.         case MULT:
  579.         case DIV:
  580.             Preced2 = 90;
  581.             break;
  582.         case POWER:
  583.             Preced2 = 110;
  584.             break;
  585.         case UNARMINUS:
  586.         case BOOL_NOT:
  587.             Preced2 = 130;
  588.             break;
  589.         case NUMBER:
  590.         case PARAMETER:
  591.         case STRING:
  592.         case OPENPARA:
  593.             Preced2 = 170;
  594.             break;
  595.  
  596.         }
  597.     }
  598.  
  599.     return Preced1 - Preced2 > 0;
  600. }
  601.  
  602. /*****************************************************************************
  603. * DESCRIPTION:                                                               *
  604. * Routine to provide a description, gievn Token and optionally a Node.       *
  605. *                                                                            *
  606. * PARAMETERS:                                                                *
  607. *   Token:      With the fault.                                              *
  608. *   Node:       Optional node at fault.                                      *
  609. *                                                                            *
  610. * RETURN VALUE:                                                              *
  611. *   char *:     Description of error.                                        *
  612. *****************************************************************************/
  613. static char *UpdateCharErrorAux(int Token, ParseTree *Node)
  614. {
  615.     static char TmpStr[LINE_LEN];
  616.     char *TokenChar = NULL;
  617.  
  618.     if (Token > 1000)
  619.     Token -= 1000;
  620.  
  621.     if (IS_NUM_FUNCTION(Token))
  622.     TokenChar = NumFuncTable[Token - NUM_FUNC_OFFSET].FuncName;
  623.     else if (IS_OBJ_FUNCTION(Token))
  624.     TokenChar = ObjFuncTable[Token - OBJ_FUNC_OFFSET].FuncName;
  625.     else if (IS_GEN_FUNCTION(Token))
  626.     TokenChar = GenFuncTable[Token - GEN_FUNC_OFFSET].FuncName;
  627.     else {
  628.         switch (Token) {
  629.             case PLUS:
  630.             TokenChar = "+";
  631.             break;
  632.             case MINUS:
  633.             TokenChar = "-";
  634.             break;
  635.         case MULT:
  636.             TokenChar = "*";
  637.             break;
  638.         case DIV:
  639.             TokenChar = "/";
  640.             break;
  641.         case POWER:
  642.             TokenChar = "^";
  643.             break;
  644.         case UNARMINUS:
  645.             TokenChar = "(Unary) -";
  646.             break;
  647.         case EQUAL:
  648.             TokenChar = "=";
  649.             break;
  650.         case COMMA:
  651.             TokenChar = ",";
  652.             break;
  653.         case COLON:
  654.             TokenChar = ":";
  655.             break;
  656.         case SEMICOLON:
  657.             TokenChar = ";";
  658.             break;
  659.         case CMP_EQUAL:
  660.             TokenChar = "==";
  661.             break;
  662.         case CMP_NOTEQUAL:
  663.             TokenChar = "!=";
  664.             break;
  665.         case CMP_LSEQUAL:
  666.             TokenChar = "<=";
  667.             break;
  668.         case CMP_GTEQUAL:
  669.             TokenChar = ">=";
  670.             break;
  671.         case CMP_LESS:
  672.             TokenChar = "<";
  673.             break;
  674.         case CMP_GREAT:
  675.             TokenChar = ">";
  676.             break;
  677.         case BOOL_AND:
  678.             TokenChar = "&&";
  679.         break;
  680.         case BOOL_OR:
  681.             TokenChar = "||";
  682.         break;
  683.         case BOOL_NOT:
  684.             TokenChar = "!";
  685.         break;
  686.         case OPENPARA:
  687.         TokenChar = "(";
  688.         break;
  689.         case CLOSPARA:
  690.         TokenChar = ")";
  691.         break;
  692.         case NUMBER:
  693.         if (Node && Node -> PObj && IP_IS_NUM_OBJ(Node -> PObj)) {
  694.             sprintf(TmpStr, "%g", Node -> PObj -> U.R);
  695.             TokenChar = TmpStr;
  696.         }
  697.         else
  698.             TokenChar = "Numeric";
  699.         break;
  700.         case PARAMETER:
  701.         if (Node && Node -> PObj && strlen(Node -> PObj -> Name) > 0)
  702.             TokenChar = Node -> PObj -> Name;
  703.         else
  704.             TokenChar = "Parameter";
  705.         break;
  706.         case STRING:
  707.         if (Node && Node -> PObj && IP_IS_STR_OBJ(Node -> PObj)) {
  708.             TokenChar = Node -> PObj -> U.Str;
  709.         }
  710.         else
  711.             TokenChar = "String";
  712.         break;
  713.         case USERINSTDEF:
  714.         case USERFUNCDEF:
  715.         case USERPROCDEF:
  716.         TokenChar = "UserFunc";
  717.         break;
  718.         default:
  719.             sprintf(TmpStr, "Token %d\n", Token);
  720.         TokenChar = TmpStr;
  721.         break;
  722.         }
  723.     }
  724.  
  725.     return TokenChar;
  726. }
  727.  
  728. /*****************************************************************************
  729. * DESCRIPTION:                                                               M
  730. * Routine to update the character error message according to StrMsg & Token  M
  731. *   Node is optional and if not NULL, will be used to get better details.    M
  732. *                                                                            *
  733. * PARAMETERS:                                                                M
  734. *   StrMsg:   Some description of error.                                     M
  735. *   Token:    Token at fault.                                                M
  736. *   Node:     Optional Node at fault.                                        M
  737. *                                                                            *
  738. * RETURN VALUE:                                                              M
  739. *   void                                                                     M
  740. *                                                                            *
  741. * KEYWORDS:                                                                  M
  742. *   UpdateCharError                                                          M
  743. *****************************************************************************/
  744. void UpdateCharError(char *StrMsg, int Token, ParseTree *Node)
  745. {
  746.     char
  747.     *TokenChar = UpdateCharErrorAux(Token, Node);
  748.         
  749.     sprintf(IPGlblCharData, "%s\"%s\"", StrMsg, TokenChar);
  750.     if (IS_AN_OPERATOR(Token) && Node) {
  751.     if (Node -> Left) {
  752.         char *StrType =
  753.         InptPrsrTypeToStr(InptPrsrTypeCheck(Node -> Left, 1));
  754.  
  755.         sprintf(&IPGlblCharData[strlen(IPGlblCharData)],
  756.             "\n\tLeft Operand: \"%s\" (%s type)",
  757.             UpdateCharErrorAux(Node -> Left -> NodeKind,
  758.                        Node -> Left),
  759.             StrType);
  760.     }
  761.     if (Node -> Right) {
  762.         char *StrType =
  763.         InptPrsrTypeToStr(InptPrsrTypeCheck(Node -> Right, 1));
  764.  
  765.         sprintf(&IPGlblCharData[strlen(IPGlblCharData)],
  766.             "\n\tRight Operand: \"%s\" (%s type)",
  767.             UpdateCharErrorAux(Node -> Right -> NodeKind,
  768.                        Node -> Right),
  769.             StrType);
  770.     }
  771.     }
  772. }
  773.  
  774. /*****************************************************************************
  775. * DESCRIPTION:                                                               *
  776. * Routine to get the next token out of the expression.                       *
  777. *   Returns next token found and sets Data to the returned value (if any).   *
  778. *                                                                            *
  779. * PARAMETERS:                                                                *
  780. *   Data:      Real numbers will be saved herein.                            *
  781. *                                                                            *
  782. * RETURN VALUE:                                                              *
  783. *   int:       Numeric value of next token.                                  *
  784. *****************************************************************************/
  785. static int GetToken(RealType *Data)
  786. {
  787.     int i,
  788.     RetVal = TOKEN_NONE;
  789.     char c;
  790.  
  791.     while (isspace(c = InptPrsrGetC(FALSE)));           /* Skip white blanks. */
  792.  
  793.     if (c == '"') {          /* Its a string token - read up to next ". */
  794.     i = 0;
  795.     while ((IPGlblCharData[i] = InptPrsrGetC(TRUE)) != '"') {
  796.         if (IPGlblCharData[i] == '\\') /* Its escape char. for next one: */
  797.         IPGlblCharData[i] = InptPrsrGetC(TRUE);
  798.         if (IPGlblCharData[i] < ' ' || i > LINE_LEN - 2) {
  799.         RetVal = TOKENERROR;
  800.         IPGlblCharData[i] = 0;
  801.         IPGlblParseError = IP_ERR_STR_TOO_LONG;
  802.         break;
  803.         }
  804.         i++;
  805.     }
  806.     if (RetVal != TOKENERROR) {
  807.         IPGlblCharData[i] = 0;
  808.         RetVal = STRING;
  809.     }
  810.     }
  811.     else if (isalpha(c)) {          /* Is it a variable/function name? */
  812.     if (islower(c))
  813.         IPGlblCharData[i = 0] = toupper(c);
  814.     else
  815.         IPGlblCharData[i = 0] = c;
  816.  
  817.     while (isalpha(c = InptPrsrGetC(FALSE)) || isdigit(c) || c == '_')
  818.         if (islower(c))
  819.         IPGlblCharData[++i] = toupper(c);
  820.         else
  821.         IPGlblCharData[++i] = c;
  822.     IPGlblCharData[++i] = 0;
  823.     InptPrsrUnGetC(c);
  824.  
  825.     if ((int) strlen(IPGlblCharData) >= OBJ_NAME_LEN) {
  826.         RetVal = TOKENERROR;
  827.         IPGlblParseError = IP_ERR_NAME_TOO_LONG;
  828.     }
  829.     else {
  830.         RetVal = GetVarFuncToken(IPGlblCharData, Data);
  831.     }
  832.     }
  833.     else if (isdigit(c) || (c == '.')) {          /* Is it numeric data? */
  834.     IPGlblCharData[i=0] = c;
  835.  
  836.     while (isdigit(c = InptPrsrGetC(FALSE)) || (c == '.') ||
  837.                     (c == 'e') || (c == 'E') || (c == 'e'))
  838.         IPGlblCharData[++i] = c;
  839.     /* Handle the special case of negative exponent ("111.111E-22"). */
  840.     if (c == '-' && (IPGlblCharData[i] == 'e' ||
  841.              IPGlblCharData[i] == 'E')) {
  842.         IPGlblCharData[++i] = c;
  843.         while (isdigit(c = InptPrsrGetC(FALSE)) || (c == '.'))
  844.         IPGlblCharData[++i] = c;
  845.     }
  846.     IPGlblCharData[++i] = 0;
  847.  
  848.     InptPrsrUnGetC(c);
  849.  
  850. #    ifdef DOUBLE
  851.         sscanf(IPGlblCharData, "%lf", Data);
  852. #    else
  853.         sscanf(IPGlblCharData, "%f", Data);
  854. #    endif /* DOUBLE */
  855.  
  856.         RetVal = NUMBER;
  857.     }
  858.     else
  859.     switch (c) {
  860.         case '+':
  861.         RetVal = PLUS;
  862.         break;
  863.         case '-':
  864.         switch (IPGlblILastToken) {
  865.             case 0:          /* If first token (no last token yet). */
  866.             case PLUS:
  867.             case MINUS:
  868.             case MULT:
  869.             case DIV:
  870.             case POWER:
  871.             case COMMA:
  872.             case EQUAL:
  873.             case CMP_EQUAL:
  874.             case CMP_NOTEQUAL:
  875.             case CMP_LSEQUAL:
  876.             case CMP_GTEQUAL:
  877.             case CMP_LESS:
  878.             case CMP_GREAT:
  879.             case BOOL_AND:
  880.             case BOOL_OR:
  881.             case BOOL_NOT:
  882.             case COLON:
  883.             case UNARMINUS:
  884.             case OPENPARA:
  885.             RetVal = UNARMINUS;
  886.             break;
  887.             default:
  888.                         RetVal = MINUS;
  889.                 break;
  890.         }
  891.         break;
  892.         case '*':
  893.         RetVal = MULT; break;
  894.         case '/':
  895.         RetVal = DIV;
  896.         break;
  897.         case '^':
  898.         RetVal = POWER;
  899.         break;
  900.         case '(':
  901.         RetVal = OPENPARA;
  902.         break;
  903.         case ')':
  904.         RetVal = CLOSPARA;
  905.         break;
  906.         case '=':
  907.         switch (c = InptPrsrGetC(FALSE)) {
  908.             case '=':
  909.                 RetVal = CMP_EQUAL;
  910.             break;
  911.             default:
  912.             InptPrsrUnGetC(c);
  913.             RetVal = EQUAL;
  914.             break;
  915.         }
  916.         break;
  917.         case '<':
  918.         switch (c = InptPrsrGetC(FALSE)) {
  919.             case '=':
  920.                 RetVal = CMP_LSEQUAL;
  921.             break;
  922.             default:
  923.             InptPrsrUnGetC(c);
  924.             RetVal = CMP_LESS;
  925.             break;
  926.         }
  927.         break;
  928.         case '>':
  929.         switch (c = InptPrsrGetC(FALSE)) {
  930.             case '=':
  931.                 RetVal = CMP_GTEQUAL;
  932.             break;
  933.             default:
  934.             InptPrsrUnGetC(c);
  935.             RetVal = CMP_GREAT;
  936.             break;
  937.         }
  938.         break;
  939.         case '&':
  940.         if ((c = InptPrsrGetC(FALSE)) == '&') {
  941.             RetVal = BOOL_AND;
  942.             break;
  943.         }
  944.         else {
  945.             RetVal = TOKENERROR;
  946.             IPGlblCharData[0] = '&';
  947.             IPGlblCharData[1] = c;
  948.             IPGlblCharData[2] = 0;
  949.             IPGlblParseError = IP_ERR_UNDEF_TOKEN;
  950.             break;
  951.         }
  952.         case '|':
  953.         if ((c = InptPrsrGetC(FALSE)) == '|') {
  954.             RetVal = BOOL_OR;
  955.             break;
  956.         }
  957.         else {
  958.             RetVal = TOKENERROR;
  959.             IPGlblCharData[0] = '|';
  960.             IPGlblCharData[1] = c;
  961.             IPGlblCharData[2] = 0;
  962.             IPGlblParseError = IP_ERR_UNDEF_TOKEN;
  963.             break;
  964.         }
  965.         case ',':
  966.         RetVal = COMMA;
  967.         break;
  968.         case ':':
  969.         RetVal = COLON;
  970.         break;
  971.         case ';':
  972.         RetVal = TOKENEND;
  973.         break;           /* End of expression! */
  974.         case '!':
  975.         if ((c = InptPrsrGetC(FALSE)) == '=') {
  976.             RetVal = CMP_NOTEQUAL;
  977.         }
  978.         else {
  979.             InptPrsrUnGetC(c);
  980.             RetVal = BOOL_NOT;
  981.         }
  982.         break;
  983.         default:
  984.         RetVal = TOKENERROR;
  985.         IPGlblCharData[0] = c;
  986.         IPGlblCharData[1] = 0;
  987.         IPGlblParseError = IP_ERR_UNDEF_TOKEN;
  988.         break;
  989.     }
  990.  
  991.     IPGlblILastToken = RetVal;
  992.  
  993.     return RetVal;
  994. }
  995.  
  996. /*****************************************************************************
  997. * DESCRIPTION:                                                               *
  998. * Routine to test alpha Token for match with one of the defined functions    *
  999. * and returns that Token function if found one.                     *
  1000. *   Otherwise it is assumed to be a user defined function or a variable.     *
  1001. *                                                                            *
  1002. * PARAMETERS:                                                                *
  1003. *   Token:     Token to search, in string function.                          *
  1004. *   Data:      Real numbers will be saved herein.                            *
  1005. *                                                                            *
  1006. * RETURN VALUE:                                                              *
  1007. *   int:       Token number                                                  *
  1008. *****************************************************************************/
  1009. static int GetVarFuncToken(char *Token, RealType *Data)
  1010. {
  1011.     int i;
  1012.     char c;
  1013.     UserDefinedFuncDefType *UserFunc;
  1014.  
  1015.     if (strcmp("COMMENT", Token) == 0) {
  1016.     /* Get first nonspace char after the COMMENT key word: */
  1017.     while (isspace(c = InptPrsrGetC(FALSE)));
  1018.     /* And read the input until this char appear again (end of comment): */
  1019.     while (c != InptPrsrGetC(FALSE));
  1020.  
  1021.     return GetToken(Data);               /* Return next token instead. */
  1022.     }
  1023.  
  1024.     for (UserFunc = UserDefinedFuncList;
  1025.      UserFunc != NULL;
  1026.      UserFunc = UserFunc -> Pnext)
  1027.     if (strcmp(UserFunc -> FuncName, Token) == 0) {
  1028.         while (isspace(c = InptPrsrGetC(FALSE)));  /* Skip white blanks. */
  1029.         InptPrsrUnGetC(c);
  1030.         if (c == '(') {
  1031.         IPGlblUserFunc = UserFunc;
  1032.         return USERINSTDEF;
  1033.         }
  1034.         else
  1035.         break;
  1036.     }
  1037.     for (i = 0; i < NumFuncTableSize; i++)        /* Is it Numeric function? */
  1038.     if (strcmp(NumFuncTable[i].FuncName, Token) == 0)
  1039.         return NumFuncTable[i].FuncToken;
  1040.     for (i = 0; i < ObjFuncTableSize; i++)       /* Is it Object function? */
  1041.     if (strcmp(ObjFuncTable[i].FuncName, Token) == 0)
  1042.         return ObjFuncTable[i].FuncToken;
  1043.     for (i = 0; i < GenFuncTableSize; i++)      /* Is it General function? */
  1044.     if (strcmp(GenFuncTable[i].FuncName, Token) == 0)
  1045.         return GenFuncTable[i].FuncToken;
  1046.  
  1047.     if (strcmp("FUNCTION", Token) == 0)
  1048.     return USERFUNCDEF;
  1049.     if (strcmp("PROCEDURE", Token) == 0)
  1050.     return USERPROCDEF;
  1051.     
  1052.     for (i = 0; i < ConstantTableSize; i++)/* Replace constant by its value. */
  1053.     if (strcmp(ConstantTable[i].FuncName, Token) == 0) {
  1054.         sprintf(Token, "%g", ConstantTable[i].Value);
  1055.         *Data = ConstantTable[i].Value;
  1056.         return NUMBER;
  1057.     }
  1058.  
  1059.     return PARAMETER;   /* If not a function - it is assumed to be variable. */
  1060. }
  1061.  
  1062. /*****************************************************************************
  1063. * DESCRIPTION:                                                               M
  1064. * Sets echo level of source irt files.                                       M
  1065. *                                                                            *
  1066. * PARAMETERS:                                                                M
  1067. *   EchoSource:  TRUE for echo, FALSE for no echo.                           M
  1068. *                                                                            *
  1069. * RETURN VALUE:                                                              M
  1070. *   void                                                                     M
  1071. *                                                                            *
  1072. * KEYWORDS:                                                                  M
  1073. *   InptPrsrEchoSource                                                       M
  1074. *****************************************************************************/
  1075. void InptPrsrEchoSource(int EchoSource)
  1076. {
  1077.     GlblEchoSource = EchoSource;
  1078. }
  1079.  
  1080. /*****************************************************************************
  1081. * DESCRIPTION:                                                               *
  1082. * Routine to control all getchar in this module and echo it if requested     *
  1083. *   Note it handles the FileStack and decrease it if end of file was found.  *
  1084. *                                                                            *
  1085. * PARAMETERS:                                                                *
  1086. *   None                                                                     *
  1087. *                                                                            *
  1088. * RETURN VALUE:                                                              *
  1089. *   char:       Next character in input stream.                              *
  1090. *****************************************************************************/
  1091. static char InptPrsrGetC(int InString)
  1092. {
  1093.     static char *p,
  1094.     Line[INPUT_LINE_LEN] = "",
  1095.     TLine[INPUT_LINE_LEN] = "";
  1096.     static int
  1097.     LineLength = 0,
  1098.     LineCount = 0;
  1099.     char c;
  1100.     int i;
  1101.  
  1102.     if (UnGetChar == 0) {               /* One level of unget char... */
  1103.     if (LineCount < LineLength) {     /* Is there anything in local Line? */
  1104.     }
  1105.     else
  1106.         do {
  1107.             if (FileStackPtr == 0) {
  1108.             WndwInputWindowGetStr(Line, INPUT_LINE_LEN);
  1109.             LineCount = 0;
  1110.             }
  1111.             else {
  1112.             sprintf(Line, "%s > ", FileStack[FileStackPtr - 1].Name);
  1113.             LineCount = strlen(Line);
  1114.             if (fgets(TLine, INPUT_LINE_LEN,
  1115.                   FileStack[FileStackPtr - 1].f) == NULL) {
  1116.                 /* Its end of file - close it and update stack. */
  1117.             TLine[0] = 0;
  1118.                 fclose(FileStack[--FileStackPtr].f);
  1119.             }
  1120.  
  1121.             /* Strip off CR/LF/TAB.  */
  1122.             for (i = LineCount, p = TLine; *p != 0; p++) {
  1123.             if (*p == 0x09)
  1124.                 do {
  1125.                 Line[i++] = ' ';
  1126.                 }
  1127.                     while ((i - LineCount) % 8 != 0);
  1128.             else if (*p < ' ' || *p > '~')
  1129.                 break;
  1130.             else
  1131.                 Line[i++] = *p;
  1132.             }
  1133.             Line[i] = 0;
  1134.             }
  1135.  
  1136.         if (GlblEchoSource)
  1137. #ifdef DJGCC
  1138.             WndwInputWindowPutStr(Line);
  1139. #else
  1140.             if (FileStackPtr != 0)     /* Input was from keyboard? */
  1141.             WndwInputWindowPutStr(Line);
  1142. #endif /* DJGCC */
  1143.  
  1144.             LineLength = strlen(Line);
  1145.         } while (LineCount >= LineLength);
  1146.  
  1147.     c = Line[LineCount++];
  1148.     if (c == '#' && !InString) {      /* Its a comment - skip that line. */
  1149.             c = ' ';                   /* Must return something. */
  1150.             LineCount = LineLength;    /* Force next time to fetch new line. */
  1151.     }
  1152. #    ifdef DEBUG1
  1153.         fprintf(stderr, "%c", c);
  1154. #    endif /* DEBUG1 */
  1155.     }
  1156.     else {
  1157.     c = UnGetChar;
  1158.     UnGetChar = 0;
  1159.     }
  1160.  
  1161.     return c;
  1162. }
  1163.  
  1164. /*****************************************************************************
  1165. * DESCRIPTION:                                                               *
  1166. * Routine to unget one char                             *
  1167. *                                                                            *
  1168. * PARAMETERS:                                                                *
  1169. *   c:        Character to unget.                                            *
  1170. *                                                                            *
  1171. * RETURN VALUE:                                                              *
  1172. *   void                                                                     *
  1173. *****************************************************************************/
  1174. static void InptPrsrUnGetC(char c)
  1175. {
  1176.     UnGetChar = c;
  1177. }
  1178.  
  1179. /*****************************************************************************
  1180. * DESCRIPTION:                                                               M
  1181. * Routine to quit reading until next ';'. If reading from files, they are    M
  1182. * all closed as well.                                 M
  1183. *                                                                            *
  1184. * PARAMETERS:                                                                M
  1185. *   FlushStdin:   If not reading from a file, should we skip to next ';'?    M
  1186. *                                                                            *
  1187. * RETURN VALUE:                                                              M
  1188. *   void                                                                     M
  1189. *                                                                            *
  1190. * KEYWORDS:                                                                  M
  1191. *   FlushToEndOfExpr                                                         M
  1192. *****************************************************************************/
  1193. void FlushToEndOfExpr(int FlushStdin)
  1194. {
  1195.     if (FileStackPtr > 0)    /* Close all the open files - back to stdin. */
  1196.     while (FileStackPtr)
  1197.         fclose(FileStack[--FileStackPtr].f);
  1198.     else if (FlushStdin && IPGlblILastToken != TOKENEND)
  1199.     while (InptPrsrGetC(FALSE) != ';');
  1200. }
  1201.  
  1202. /*****************************************************************************
  1203. * DESCRIPTION:                                                               M
  1204. * Routine to push new file to read on the FileStack from INCLUDE command:    M
  1205. *                                                                            *
  1206. * PARAMETERS:                                                                M
  1207. *   PrmFileName:  Name of file to start to read from.                        M
  1208. *                                                                            *
  1209. * RETURN VALUE:                                                              M
  1210. *   void                                                                     M
  1211. *                                                                            *
  1212. * KEYWORDS:                                                                  M
  1213. *   FileInclude                                                              M
  1214. *****************************************************************************/
  1215. void FileInclude(char *PrmFileName)
  1216. {
  1217.     int i;
  1218.     FILE *f;
  1219.     char s[LINE_LEN], FileName[LINE_LEN], c, *p;
  1220.  
  1221.     if (FileStackPtr < FILE_STACK_SIZE) {
  1222.     strcpy(FileName, PrmFileName);
  1223.  
  1224.       if ((p = strstr(FileName, ".irt")) == NULL)
  1225.         strcat(FileName, ".irt");
  1226.  
  1227.     if ((f = fopen(FileName, "r")) != NULL) {
  1228.         FileStack[FileStackPtr].f = f;
  1229.         for (i = strlen(FileName) - 1;       /* Isolate the file name. */
  1230.          i > 0 && (c = FileName[i]) != '\\' && c != '/' && c != ':';
  1231.          i--);
  1232.         if (i > 0)
  1233.         i++;
  1234.         strncpy(FileStack[FileStackPtr].Name, &FileName[i],
  1235.                             FILE_NAME_LEN - 1);
  1236.         FileStackPtr++;         /* Now next char is from that file! */
  1237.     }
  1238.     else {
  1239.         sprintf(s, "Cannt open file %s - ignored", FileName);
  1240.         WndwInputWindowPutStr(s);
  1241.     }
  1242.     }
  1243.     else
  1244.     WndwInputWindowPutStr("File nesting too deep - ignored");
  1245. }
  1246.  
  1247. /*****************************************************************************
  1248. * DESCRIPTION:                                                               M
  1249. * Routine to return parsing error if happen one, zero return value otherwise.M
  1250. *                                                                            *
  1251. * PARAMETERS:                                                                M
  1252. *   Message:                                                                 M
  1253. *                                                                            *
  1254. * RETURN VALUE:                                                              M
  1255. *   InptPrsrEvalErrType:                                                     M
  1256. *                                                                            *
  1257. * KEYWORDS:                                                                  M
  1258. *   InptPrsrParseError                                                       M
  1259. *****************************************************************************/
  1260. InptPrsrEvalErrType InptPrsrParseError(char **Message)
  1261. {
  1262.     InptPrsrEvalErrType Temp;
  1263.  
  1264.     *Message = IPGlblCharData;
  1265.     Temp = IPGlblParseError;
  1266.     IPGlblParseError = IPE_NO_ERR;
  1267.     return Temp;
  1268. }
  1269.